package de.hsma.srn.view;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Desktop;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;

import javax.swing.AbstractListModel;
import javax.swing.DefaultListModel;
import javax.swing.JCheckBox;
import javax.swing.JFileChooser;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListCellRenderer;
import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants;
import javax.swing.border.TitledBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import de.hsma.srn.controller.KeyBoxController;
import de.hsma.srn.interfaces.IListener;
import de.hsma.srn.model.account.DomainModel;
import de.hsma.srn.view.components.Button;
import de.hsma.srn.view.components.Frame;
import de.hsma.srn.view.components.Label;
import de.hsma.srn.view.components.List;

/**
 * 
 * @author Tommy Vinh Lam
 * 
 */
public class KeyBoxView extends Frame implements IListener {
	/**
	 * generated serialVersionUID
	 */
	private static final long serialVersionUID = -7038304904543787840L;
	/**
	 * The Controller to operate with
	 */
	private KeyBoxController mKeyBoxController;
	// The Panels
	private Label lblTitle;
	private JPanel panelMyKeys;
	private JPanel panelAssignedKeys;
	private JPanel panelMenu;

	// The Buttons
	private Button btnCreateKey;
	private Button btnUseKey;
	private Button btnShareKey;
	private Button btnDeleteKey;

	// The lists
	private List listMyOwnKeys;
	private List listForeignKeys;
	private List listSharedUser;

	// The MouseAdpter for checkboxes in lists
	private MouseAdapter mMouseAdapter = new MouseAdapter() {
		@Override
		public void mouseClicked(MouseEvent event) {
			if (listSharedUser != null) {
				int index = listSharedUser.locationToIndex(event.getPoint());
				CheckListItem item = (CheckListItem) listSharedUser.getModel()
						.getElementAt(index);
				item.setSelected(!item.isSelected());
				listSharedUser.repaint(listSharedUser.getCellBounds(index,
						index));
			}
		}
	};

	/*
	 * Constructors
	 */
	/**
	 * Create a new KeyBox GUI
	 * 
	 * @param keyBoxController
	 */
	public KeyBoxView(KeyBoxController keyBoxController) {
		this.mKeyBoxController = keyBoxController;
		this.mKeyBoxController.addListener(this);
		this.addWindowListener(new WindowListener() {
			@Override
			public void windowActivated(WindowEvent e) {
			}

			@Override
			public void windowClosed(WindowEvent e) {
			}

			@Override
			public void windowClosing(WindowEvent e) {
				System.out
						.println("[VIEW] KeyBox: Fenster geschlossen - melde User ab...");
				mKeyBoxController.logout();
			}

			@Override
			public void windowDeactivated(WindowEvent e) {
			}

			@Override
			public void windowDeiconified(WindowEvent e) {
			}

			@Override
			public void windowIconified(WindowEvent e) {
			}

			@Override
			public void windowOpened(WindowEvent e) {
			}
		});
		initialize();
		initializeActions();
	}

	/*
	 * Public Methods (non-Javadoc)
	 * 
	 * @see
	 * de.hsma.srn.interfaces.IListener#update(de.hsma.srn.model.account.DomainModel
	 * )
	 */
	/**
	 * This method is called when the model get changed. You can access the data
	 * via the member mKeyBoxController or the given DomainModel! Normally here
	 * all the view components should update themselves!
	 */
	@Override
	public void update(DomainModel domain) {
		// Refresh the list with own keys

		// refreshMyOwnKeysList();
		listMyOwnKeys.setModel(new AbstractListModel() {
			/**
		 *
		 */
			private static final long serialVersionUID = -235977435798839893L;
			String[] values = mKeyBoxController.getOwnKeys();

			@Override
			public int getSize() {
				return values.length;
			}

			@Override
			public Object getElementAt(int index) {
				return values[index];
			}
		});
		// Refresh the list with foreign keys
		// refreshForeignKeys();

		this.listForeignKeys.setModel(new AbstractListModel() {
			/**
		 *
		 */
			private static final long serialVersionUID = -8640430325312762508L;
			String[] values = mKeyBoxController.getAssignedKeys();

			@Override
			public int getSize() {
				return values.length;
			}

			@Override
			public Object getElementAt(int index) {
				return values[index];
			}
		});
		// Refresh the usernames
		// String[] sharedUser = mKeyBoxController.getAllUsernames();
		// DefaultListModel defaultListModel = new DefaultListModel();
		// listSharedUser.setCellRenderer(new CheckListRenderer());
		// for (int i = 0; i < sharedUser.length; i++) {
		// defaultListModel.addElement(new CheckListItem(sharedUser[i]));
		// }
		// listSharedUser.setModel(defaultListModel);
		refreshSharedUserList();
	}

	/*
	 * Internal methods
	 */
	private void initializeActions() {

		// Set focus only on one list
		this.listForeignKeys.addFocusListener(new FocusListener() {
			@Override
			public void focusGained(FocusEvent arg0) {
				panelAssignedKeys.setVisible(false);
				btnShareKey.setVisible(false);
				// btnRemoveKey.setVisible(false);
				btnCreateKey.setVisible(false);
				listMyOwnKeys.clearSelection();

			}

			@Override
			public void focusLost(FocusEvent arg0) {
			}
		});

		// ActionListener listMyOwnKeys
		this.listMyOwnKeys.addFocusListener(new FocusListener() {
			@Override
			public void focusGained(FocusEvent arg0) {
				panelAssignedKeys.setVisible(true);
				btnCreateKey.setVisible(true);
				btnShareKey.setVisible(true);
				// btnRemoveKey.setVisible(true);
				listForeignKeys.clearSelection();
			}

			@Override
			public void focusLost(FocusEvent arg0) {

			}
		});

		this.listMyOwnKeys
				.addListSelectionListener(new ListSelectionListener() {

					@Override
					public void valueChanged(ListSelectionEvent e) {
						refreshSharedUserList();
					}
				});

		// btnCreate Key ActionListener
		this.btnCreateKey.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				JFileChooser fileChooser = new JFileChooser();
				fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
				fileChooser.setCurrentDirectory(new File(mKeyBoxController
						.getHomePath()));
				fileChooser
						.setDialogTitle("Waehlen Sie eine Datei zur Verschluesselung aus");
				int returnVal = fileChooser.showOpenDialog(fileChooser);
				if (returnVal == JFileChooser.APPROVE_OPTION) {
					File file = fileChooser.getSelectedFile();
					String absolutePath = file.getAbsolutePath();
					String relativeBase = (new File(".")).getAbsolutePath();
					String relativePath = absolutePath.substring(relativeBase
							.length() - 1);
					mKeyBoxController.createKey(relativePath);
				}
			}
		});

		// btnUseKey ActionListener
		this.btnUseKey.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				String filepath;
				if ((filepath = listMyOwnKeys.getSelectedValue()) == null) {
					filepath = listForeignKeys.getSelectedValue();
				}
				if (filepath != null) {
					// call the controller with this path
					mKeyBoxController.useKey(filepath);
					// Check if the key is my own
					File file = null;
					for(String keyPackagePath : mKeyBoxController.getOwnKeys()) {
						if(keyPackagePath.equalsIgnoreCase(filepath)) {
							file = new File(mKeyBoxController.getHomePath() + "/decrypted" + (new File(filepath)).getName());
						}
					}
					if(file==null) {
						file = new File(mKeyBoxController.getHomePath() + "/" + (new File(filepath)).getName());
					}
					try {
						Desktop.getDesktop().open(file);
					} catch (IOException e) {
						System.err.println("Konnte Datei " + file.getPath() + " nicht oeffnen - Datei existiert nicht!"); 
					}
				}
			}
		});

		// btnShareKey ActionListener
		this.btnShareKey.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				// int counter = 0;
				String filename = listMyOwnKeys.getSelectedValue();
				// for (int i = 0; i < listSharedUser.getModel().getSize(); i++)
				// {
				// CheckListItem checkListItem = (CheckListItem) listSharedUser
				// .getModel().getElementAt(i);
				// if (checkListItem.isSelected) {
				// counter++;
				// }
				// }
				java.util.List<String> newSharedUser = new ArrayList<String>();
				// String[] newSharedUser = new String[counter];
				for (int i = 0; i < listSharedUser.getModel().getSize(); i++) {
					CheckListItem checkListItem = (CheckListItem) listSharedUser
							.getModel().getElementAt(i);
					if (checkListItem.isSelected) {
						// newSharedUser[i] = checkListItem.toString();
						newSharedUser.add(checkListItem.toString());
					}
				}
				System.out.println("Share to " + newSharedUser.toString());
				// mKeyBoxController.shareKey(filename, newSharedUser);
				mKeyBoxController.shareKey(filename,
						newSharedUser.toArray(new String[0]));
				System.out.println("Shared!");
			}
		});

		this.btnDeleteKey.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent ac) {
				String filepath;
				if ((filepath = listMyOwnKeys.getSelectedValue()) == null) {
					filepath = listForeignKeys.getSelectedValue();
				}
				if(filepath!=null && !filepath.isEmpty()) {
					mKeyBoxController.deleteKey(filepath);
				}
			}
		});

	}

	/**
	 * refreshSharedUserList() method
	 */
	private void refreshSharedUserList() {
		String[] allUser = mKeyBoxController.getAllUsernames();
		String[] sharedUser = mKeyBoxController
				.getSharedUsersOfKey(listMyOwnKeys.getSelectedValue());

		DefaultListModel defaultListModel = new DefaultListModel();

		for (int i = 0; i < allUser.length; i++) {
			boolean isSharedUser = false;
			for (int j = 0; j < sharedUser.length; j++) {
				if (allUser[i].equalsIgnoreCase(sharedUser[j])) {
					isSharedUser = true;
				}
			}
			defaultListModel.addElement(new CheckListItem(allUser[i],
					isSharedUser));
		}
		listSharedUser.setModel(defaultListModel);
		listSharedUser.setCellRenderer(new CheckListRenderer());
	}

	private void initialize() {
		getContentPane().setLayout(new BorderLayout(0, 0));
		// The panels
		lblTitle = new Label(mKeyBoxController.getUsername() + "'s Keybox"); // Not
																				// really
																				// a
																				// panel
																				// but
																				// treated
																				// as
																				// one
		lblTitle.setVerticalAlignment(SwingConstants.TOP);
		lblTitle.setFont(new Font("Helvetica Neue", Font.PLAIN, 20));
		getContentPane().add(lblTitle, BorderLayout.NORTH);
		// The My Keys Panel
		JPanel panelKeyBox = new JPanel();
		getContentPane().add(panelKeyBox, BorderLayout.CENTER);
		panelKeyBox.setLayout(new GridLayout(0, 1, 0, 0));
		// The overall panel for myOwnKeys and the SharedUser panel
		panelMyKeys = new JPanel();
		panelKeyBox.add(panelMyKeys);
		panelMyKeys.setLayout(new GridLayout(1, 0, 0, 0));
		// Panel own keys with list
		JPanel panelMyOwnKeys = new JPanel();
		panelMyOwnKeys.setBorder(new TitledBorder(null, "My keys",
				TitledBorder.LEADING, TitledBorder.TOP, null, null));
		panelMyKeys.add(panelMyOwnKeys);
		panelMyOwnKeys.setLayout(new GridLayout(1, 0, 0, 0));
		// MyOwnKeys List
		listMyOwnKeys = new List();
		listMyOwnKeys.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		listMyOwnKeys.setModel(new AbstractListModel() {
			/**
		 *
		 */
			private static final long serialVersionUID = -8986806628567011281L;
			String[] values = mKeyBoxController.getOwnKeys();

			@Override
			public int getSize() {
				return values.length;
			}

			@Override
			public Object getElementAt(int index) {
				return values[index];
			}
		});
		// refreshMyOwnKeysList();

		JScrollPane scrollPaneMyOwnKeys = new JScrollPane(listMyOwnKeys);
		panelMyOwnKeys.add(scrollPaneMyOwnKeys);
		// Panel for granted user - will be added later dynamically
		panelAssignedKeys = new JPanel();
		panelAssignedKeys.setBorder(new TitledBorder(null, "Granted User",
				TitledBorder.RIGHT, TitledBorder.TOP, null, null));
		panelMyKeys.add(panelAssignedKeys);
		panelAssignedKeys.setLayout(new GridLayout(0, 1, 0, 0));
		listSharedUser = new List();
		listSharedUser.addMouseListener(mMouseAdapter);
		JScrollPane scrollPaneSharedUser = new JScrollPane(listSharedUser);
		panelAssignedKeys.add(scrollPaneSharedUser);
		// Panel for the foreign keys with list
		JPanel panelForeignKeys = new JPanel();
		panelForeignKeys.setBorder(new TitledBorder(null, "Foreign keys",
				TitledBorder.LEADING, TitledBorder.TOP, null, null));
		panelKeyBox.add(panelForeignKeys);
		panelForeignKeys.setLayout(new GridLayout(1, 0, 0, 0));
		listForeignKeys = new List();
		listForeignKeys.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		listForeignKeys.setModel(new AbstractListModel() {
			/**
		 *
		 */
			private static final long serialVersionUID = -499631435848251439L;
			String[] values = mKeyBoxController.getAssignedKeys();

			@Override
			public int getSize() {
				return values.length;
			}

			@Override
			public Object getElementAt(int index) {
				return values[index];
			}
		});
//		refreshForeignKeys();
		JScrollPane scrollPane = new JScrollPane(listForeignKeys);
		panelForeignKeys.add(scrollPane);

		panelMenu = new JPanel();
		FlowLayout flowLayout = (FlowLayout) panelMenu.getLayout();
		flowLayout.setAlignment(FlowLayout.RIGHT);
		getContentPane().add(panelMenu, BorderLayout.SOUTH);

		btnCreateKey = new Button("Create Key");
		panelMenu.add(btnCreateKey);
		btnUseKey = new Button("Use");
		panelMenu.add(btnUseKey);
		btnShareKey = new Button("Share");
		panelMenu.add(btnShareKey);
		// btnRemoveKey = new Button("Deny");
		// panelMenu.add(btnRemoveKey);
		btnDeleteKey = new Button("Delete");
		panelMenu.add(btnDeleteKey);
	}

	class CheckListItem {
		private String label;
		private boolean isSelected = false;

		public CheckListItem(String label) {
			this.label = label;
		}

		public CheckListItem(String label, boolean isSelected) {
			this(label);
			this.isSelected = isSelected;
		}

		public boolean isSelected() {
			return isSelected;
		}

		public void setSelected(boolean isSelected) {
			this.isSelected = isSelected;
		}

		@Override
		public String toString() {
			return label;
		}
	}

	class CheckListRenderer extends JCheckBox implements ListCellRenderer {
		/**
		 * generated serialVersionUID
		 */
		private static final long serialVersionUID = 296999802002672816L;

		@Override
		public Component getListCellRendererComponent(JList list, Object value,
				int index, boolean isSelected, boolean hasFocus) {
			setEnabled(list.isEnabled());
			setSelected(((CheckListItem) value).isSelected());
			setFont(list.getFont());
			setBackground(list.getBackground());
			setForeground(list.getForeground());
			setText(value.toString());
			return this;
		}
	}
}
